package apof.dao.datapool
{
	import flash.utils.Dictionary;
	import apof.dao.Dao;
	import apof.model.ApofModel;
	import apof.util.IdCreater;
	
	public class ObjPool
	{
		private var classInfo:Object;
		private var callback:Function;
		public var all:Array=new Array();
		public var pk:Dictionary=new Dictionary();
		public var fk:Dictionary=new Dictionary();
		public static var dp:DataPool;
		
		public function ObjPool(clazz:Class , callback:Function) {
			this.callback=callback;
			this.classInfo=clazz["classInfo"];
			Dao.retrive3(clazz,null,fillData);
		}
		
		private function fillData(arr:Array):void {
			for each(var item:ApofModel in arr) {
				fillItem(item);
			}
			callback();
		}
		
		private function fillItem(item:ApofModel):void {
				all.push(item);
				pk[item[classInfo.primaryKey]]=item;
				for (var fkName:String in classInfo.foreignKey) {
					if(classInfo.foreignKey[fkName].aggregate) continue;
					if(fk[fkName]==null)
						fk[fkName]=new Dictionary();
					if(fk[fkName][item[fkName]]==null)
						fk[fkName][item[fkName]]=new Array();
					fk[fkName][item[fkName]].push(item);
				}			
		}
		
		public function link():void {
			for each(var item:ApofModel in all) {
				linkItem(item);
			}
		}
		
		private function linkItem(item:ApofModel):void {
			for (var fkName:String in classInfo.foreignKey) {
				if(!classInfo.foreignKey[fkName].aggregate)
					linkItemField(item,fkName);
			}			
		} 
		
		private function linkItemField(item:ApofModel, field:String ):void {
			relinkItemField(item,field);
		}
		
		private function relinkItemField( item:ApofModel,  fkName:String , newValue:int=-1):void {
			var oldValue:int;
			if(newValue!=-1) {
				oldValue=item[fkName];
				item[fkName]=newValue;
			}else {
				oldValue=-1;
				newValue=item[fkName];
			}
			var fkInfo:Object=classInfo.foreignKey[fkName];
			var targetClass:Class=fkInfo.linkto;
			var target:Object=dp.retrive(targetClass,item[fkName]);
			var oldTarget:Object=(oldValue!=-1)?(dp.retrive(targetClass,oldValue)):null;
						
			//link out
			if(!fkInfo.aggregate)
				item[fkInfo.ref]=target;
			else 
				item[fkName].push(target);	
				
			//link-back
			
			var peerName:String=fkInfo.peerlink;
			var peerInfo:Object=targetClass["classInfo"].foreignKey[peerName];
			//remove old link-back
			if(oldTarget) {
				removeLink(dp.retrive(targetClass,oldValue),peerName);
			}
			//establish new link-back
			addLink(dp.retrive(targetClass,newValue),peerName,item[classInfo.primaryKey]);			
		}
		
		public static function removeFromArray(arr:Array, target:Object):void {
			arr.splice(arr.indexOf(target),1);
		}
		
		private static function removeLink(target:ApofModel,field:String):void {
			if(!field || !target)return;
			var fkInfo:Object=target["classInfo"].foreignKey[field];
			if(!fkInfo.aggregate){
				target[field]=null;
				target[fkInfo.ref]=null;
			}				
			else 
				removeFromArray(target[field] as Array,target);	
		}
		
		private static function  addLink(item:ApofModel,field:String,value:int):void {
			if(!field || !item)return;
			var fkInfo:Object=item["classInfo"].foreignKey[field];
			var targetClass:Class=fkInfo.linkto;
			var target:Object=dp.retrive(targetClass,value);			
			if(!fkInfo.aggregate){
				item[field]=value;
				item[fkInfo.ref]=target;
			}				
			else 
				(item[field] as Array).push(target);	
		}
		
		public function createWithID(target:ApofModel):void {
			fillItem(target);
			linkItem(target);
			Dao.create(target);
		}
		
		public function create(target:ApofModel):void {
			target[classInfo.primaryKey]=IdCreater.create();
			createWithID(target);
		}
		
		public function update(target:ApofModel):void {
			Dao.update(target);
		}
		
		public function updateRef(target:ApofModel,fkName:String ,value:int):void {
			removeFromArray(fk[fkName][target[fkName]] as Array , target);
			relinkItemField(target,fkName,value);
			fk[fkName][value].push(target);
			Dao.update(target);			
		}
		
		public function remove(target:ApofModel):void
		{
			for(var fkName:String in classInfo.foreignKey) {
				var fkInfo:Object=classInfo.foreignKey[fkName];
				var peerName:String=fkInfo.peerlink;
				if(fkInfo.aggregate) {
					for each(var theOther:ApofModel in target[fkName]) {
						removeLink(theOther,peerName);
					}
				}else  {
					var another:ApofModel=dp.retrive(fkInfo.linkto,target[fkName]);
					removeLink(another,peerName);
					//维护外键索引
					removeFromArray(fk[fkName][target[fkName]] as Array,target);				}

			}
			//维护主键索引
			removeFromArray(all,target);
			delete pk[target[classInfo.primaryKey]];
			Dao.remove1(target);
		}
		
		public function removeById(id:int):void {
			remove(retrive(id));
		}
		
		public function retrive(id:int):ApofModel{
			return pk[id];
		}
	}
}







